// 定义级数系数
const COEFFICIENTS = [
    0.99999999999999709182, 57.156235665862923517, -59.597960355475491248,
    14.136097974741747174, -0.49191381609762019978, 0.33994649984811888699e-4,
    0.46523628927048575665e-4, -0.98374475304879564677e-4,
    0.15808870322491248884e-3, -0.21026444172410488319e-3,
    0.2174396181152126432e-3, -0.16431810653676389022e-3,
    0.84418223983852743293e-4, -0.2619083840158140867e-4,
    0.36899182659531622704e-5
];

const g = 607 / 128;
const LOGSQRT2PI = Math.log(Math.sqrt(2 * Math.PI));

/**
 * 使用Lanczos近似法计算[伽马函数](https://en.wikipedia.org/wiki/Gamma_function)的对数值。
 * 该函数接受任何大于0的实数n作为输入。
 * 该函数对于普通伽马函数无法处理的大数值n（n > 165）非常有用。
 * 代码基于Lanczos的伽马近似法，定义见[此处](http://my.fit.edu/~gabdo/gamma.txt)。
 *
 * @param {number} n 任何大于零的实数。
 * @returns {number} 输入值的伽马函数的对数值。
 *
 * @example
 * gammaln(500); // 2605.1158503617335
 * gammaln(2.4); // 0.21685932244884043
 */
function gammaln(n) {
    // 如果值不在定义域内，返回无穷大
    if (n <= 0) {
        return Number.POSITIVE_INFINITY;
    }

    // 递减n，因为近似法是为n - 1定义的
    n--;

    // 创建级数近似
    let a = COEFFICIENTS[0];

    for (let i = 1; i < 15; i++) {
        a += COEFFICIENTS[i] / (n + i);
    }

    const tmp = g + 0.5 + n;

    // 返回伽马函数的自然对数
    return LOGSQRT2PI + Math.log(a) - tmp + (n + 0.5) * Math.log(tmp);
}

export default gammaln;
